import { IBaseStyle, IImageStyle, IPosterStyle, IPosterTemplate, ITextStyle } from "./parser";

export interface IPosterEditorOptions {
  onFocus?: (style: IPosterStyle, index: number) => void;
}

export default class PosterEditor {
  private _root: HTMLElement;
  private _container: HTMLDivElement = document.createElement("div");
  private _focus: HTMLElement | null = null;
  private _elements: HTMLElement[] = [];
  constructor(root: string | HTMLElement, private _template: IPosterTemplate, private _options?: IPosterEditorOptions) {
    const ele = typeof root === "string" ? document.getElementById(root) : root;
    if (!ele) {
      throw new Error("container element not found");
    }
    this._root = ele;

    this._init();
  }

  private _init() {
    const { width, height } = this._template.view;
    this._container.style.width = width + "px";
    this._container.style.height = height + "px";
    this._root.appendChild(this._container);

    const styles = this._template.elements;
    for (let i = 0; i < styles.length; i++) {
      const style = styles[i];
      const element = this._createElement(style);
      element.onclick = () => {
        this._cleanFocus();

        if (style.editable) {
          this._focus = element;
          element.classList.add("focus");
          this._options?.onFocus?.(style, i);
        }
      };
      this._elements.push(element);
      this._container.appendChild(element);
    }
  }

  private _cleanFocus() {
    if (this._focus) {
      this._focus.classList.remove("focus");
      this._focus = null;
    }
  }

  private _createElement(style: IPosterStyle): HTMLElement {
    switch (style.type) {
      case "IMAGE":
        return this._createImageElement(style);
      case "TEXT":
        return this._createTextElement(style);
    }
  }

  private _createImageElement(style: IImageStyle): HTMLElement {
    const { src } = style;
    const img = document.createElement("img");
    img.src = src;

    this._setBaseStyle(img, style);

    return img;
  }

  private _createTextElement(style: ITextStyle): HTMLElement {
    const { content } = style;
    const text = document.createElement("span");
    const str = content.split("\n").join("</br>");
    text.innerHTML = str;

    this._setTextStyle(text, style);

    return text;
  }

  private _setTextStyle(text: HTMLSpanElement, style: ITextStyle) {
    const { algin = "left", fontSize = 12, fontFamily = "", color = "" } = style;
    this._setBaseStyle(text, style);
    text.style.display = "inline-block";
    text.style.lineHeight = "1";
    text.style.wordWrap = "break-word";
    text.style.textAlign = algin;
    text.style.fontSize = fontSize + "px";
    text.style.fontFamily = fontFamily;
    text.style.color = color;
  }

  private _setBaseStyle(ele: HTMLElement, style: IBaseStyle) {
    const { width = 0, height = 0, x = 0, y = 0 } = style;
    ele.style.width = width + "px";
    ele.style.height = height + "px";
    ele.style.left = x + "px";
    ele.style.top = y + "px";
    ele.style.position = "absolute";
    if (style.editable) {
      ele.className = "edit_ele";
    }
  }

  setContent(content: string, index: number) {
    const ele = this._elements[index];
    const style = this._template.elements[index];
    this._updateElementContent(ele, style, content);
  }

  private _updateElementContent(ele: HTMLElement, style: IPosterStyle, content: string) {
    if (ele) {
      switch (style.type) {
        case "IMAGE":
          {
            (ele as HTMLImageElement).src = content;
            style.src = content;
          }
          break;
        case "TEXT":
          {
            const str = content.split("\n").join("</br>");
            ele.innerHTML = str;
            style.content = content;
          }
          break;
      }
    }
  }
}
